import tester.*;

/**
 * @author Adam Blackwell & Ryan Cassidy
 */
// All the examples and tests for all things Account like.
@Example
public class Examples {

	// The default constructor.
	public Examples() {
	}

	// Initialize the checking accounts.
	IAccount check1 = new Checking(0001, 0, "First Checking Account", 0);
	IAccount check2 = new Checking(0002, 100, "Second Checking Account", 50);
	IAccount check3 = new Checking(0003, 500, "Third Checking Account", 0);
	// Initialize the savings accounts.
	IAccount savings1 = new Savings(0004, 0, "First Savings Account", 4.9);
	IAccount savings2 = new Savings(0005, 100, "Second Savings Account", 8.9);
	IAccount savings3 = new Savings(0006, 0, "Third Savings Account", 1.1);
	// Initialize the savings accounts.
	// 1000 credit line approved, 1000 borrowed already
	IAccount credit1 = new Credit(0004, 1000, "First Credit Account", 1000, 4.9);
	// 200 credit line approved, 100 borrowed already
	IAccount credit2 = new Credit(0005, 100, "Second Credit Account", 200, 8.9);
	// 1000 credit line approved, no money borrowed yet
	IAccount credit3 = new Credit(0006, 0, "Third Credit Account", 1000, 1.1);
	// Initialize the checking accounts.
	IAccount pcheck1 = new PremiumChecking(0001, 0,
			"First Checking Account", 0, 0);
	IAccount pcheck2 = new PremiumChecking(0002, 100,
			"Second Checking Account", 50, 5);
	IAccount pcheck3 = new PremiumChecking(0003, 500,
			"Third Checking Account", 0, 25);

	// Tests the exceptions we expect to be thrown when
	// performing an "illegal" action.
	@TestMethod
	public void testExceptions(Tester t) {
		// test that check1.withdraw(100) throws a RuntimeException
		// with the message "Insufficient Funds".
		t.checkExpect(
				// optional description of the test case
				"The test should pass, we supplied the right information",
				// the exception we expect to throw
				new RuntimeException(
				"Insufficient Funds in the checking account."),
				// the object that invokes the method that throws the exception
				check1,
				// the name of the method that should throw exception
				"withdraw",
				// arguments for the method invocation - as many as are needed,
				// or none
				100);

		// test that savings1.withdraw(100) throws a RuntimeException
		// with the message "Insufficient Funds".
		t.checkExpect(
				"The test should pass, we supplied the right information",
				new RuntimeException(
				"Insufficient Funds in the savings account."),
				savings1, "withdraw", 100);

		// test that credit1.withdraw(100) throws a RuntimeException
		// with the message "Insufficient Funds".
		t.checkExpect(
				"The test should pass, we supplied the right information",
				new RuntimeException(
				"Cannot spend above your credit line First Credit Account."),
				credit1, "withdraw", 100);

		// test the pcheck1.withdraw(100) throws a RuntimeExeption
		// with the message "Insufficient Funds".
		t.checkExpect("Blah", 
				new RuntimeException(
				"Insufficient Funds in the checking account."), 
				pcheck1, "withdraw", 100);
		
		// Tests the deposit methods.
		// test that credit1.deposit(1100) throws a RuntimeException
		// with the message "Insufficient Funds".
		t.checkExpect(
				// optional description of the test case
				"The test should pass, we supplied the right information",
				// the exception we expect to throw
				new RuntimeException(
				"Cannot have a credit on your account."),
				// the object that invokes the method that throws the exception
				credit1,
				// the name of the method that should throw exception
				"deposit",
				// arguments for the method invocation - as many as are needed,
				// or none
				1100);
	}

	// Tests the withdraw methods inside certain accounts.
	@TestMethod
	public void testWithdraw(Tester t) {
		t.checkExpect(check2.withdraw(49), new Checking(0002, 51,
				"Second Checking Account", 50));
		t.checkExpect(savings2.withdraw(100), new Savings(0005, 0,
				"Second Savings Account", 8.9));
		t.checkExpect(credit2.withdraw(100), new Credit(0005, 200,
				"Second Credit Account", 200, 8.9));
		t.checkExpect(credit2.withdraw(100), new Credit(0005, 200,
				"Second Credit Account", 200, 8.9));
		t.checkExpect(credit2.withdraw(100), new Credit(0005, 200,
				"Second Credit Account", 200, 8.9));
		t.checkExpect(credit2.withdraw(100), new Credit(0005, 200,
				"Second Credit Account", 200, 8.9));
		t.checkExpect(pcheck1.withdraw(0), new PremiumChecking(0001, 0,
				"First Checking Account", 0, 0));
		t.checkExpect(pcheck2.withdraw(50), new PremiumChecking(0002, 50,
				"Second Checking Account", 50, 5));
	}

	// Tests the deposit methods inside each type ofAAcount.
	@TestMethod
	public void testDeposit(Tester t) {
		t.checkExpect(check1.deposit(100), new Checking(0001, 100,
				"First Checking Account", 0));
		t.checkExpect(check2.deposit(500), new Checking(0002, 600,
				"Second Checking Account", 50));
		t.checkExpect(savings1.deposit(100), new Savings(0004, 100,
				"First Savings Account", 4.9));
		t.checkExpect(savings2.deposit(100), new Savings(0005, 200,
				"Second Savings Account", 8.9));
		t.checkExpect(credit1.deposit(100), new Credit(0004, 900,
				"First Credit Account", 1000, 4.9));
		t.checkExpect(credit2.deposit(100), new Credit(0005, 0,
				"Second Credit Account", 200, 8.9));
		t.checkExpect(pcheck1.deposit(100), new PremiumChecking(0001, 100,
				"First Checking Account", 0, 5));
		t.checkExpect(pcheck2.deposit(500), new PremiumChecking(0002, 600,
				"Second Checking Account", 50, 35));
	}

	// Tests the canWithdraw method inside each type ofAAcount.
	@TestMethod
	public void testCanWithdraw(Tester t) {
		t.checkExpect(check1.canWithdraw(100), false);
		t.checkExpect(check2.canWithdraw(100), true);
		t.checkExpect(savings1.canWithdraw(100), false);
		t.checkExpect(savings2.canWithdraw(100), true);
		t.checkExpect(credit1.canWithdraw(100), true);
		t.checkExpect(credit2.canWithdraw(100), true);
		t.checkExpect(pcheck1.canWithdraw(0), true);
		t.checkExpect(pcheck2.canWithdraw(600), false);
	}

	// Test toSavings
	@TestMethod
	public void testExceptionsTo(Tester t) {
		// Test toChecking
		t.checkExpect(
				// optional description of the test case
				"The test should pass, we supplied the right information",
				// the exception we expect to throw
				new RuntimeException("This is the wrong type of account"),
				// the object that invokes the method that throws the exception
				savings1,
				// the name of the method that should throw exception
				"toChecking");

		// Test toSavings
		t.checkExpect(
				// optional description of the test case
				"The test should pass, we supplied the right information",
				// the exception we expect to throw
				new RuntimeException("This is the wrong type of account"),
				// the object that invokes the method that throws the exception
				credit1,
				// the name of the method that should throw exception
				"toSavings");

		// Test toCredit
		t.checkExpect(
				// optional description of the test case
				"The test should pass, we supplied the right information",
				// the exception we expect to throw
				new RuntimeException("This is the wrong type of account"),
				// the object that invokes the method that throws the exception
				check1,
				// the name of the method that should throw exception
				"toCredit");

		// Test toSavings
		t.checkExpect(
				// optional description of the test case
				"The test should pass, we supplied the right information",
				// the exception we expect to throw
				new RuntimeException("This is the wrong type of account"),
				// the object that invokes the method that throws the exception
				savings1,
				// the name of the method that should throw exception
				"toPremiumChecking");
	}

	// Test isChecking
	@TestMethod
	public void testIsChecking(Tester t) {
		t.checkExpect(credit1.isChecking(), false);
		t.checkExpect(check2.isChecking(), true);
		t.checkExpect(pcheck2.isChecking(), false);
	}

	// Test isCredit
	@TestMethod
	public void testIsCredit(Tester t) {
		t.checkExpect(credit1.isCredit(), true);
		t.checkExpect(check2.isCredit(), false);
	}

	// Test isSavings
	@TestMethod
	public void testIsSavings(Tester t) {
		t.checkExpect(check1.isSavings(), false);
		t.checkExpect(savings2.isSavings(), true);
	}

	// Test isPremiumChecking
	@TestMethod
	public void testIsPremiumChecking(Tester t) {
		t.checkExpect(check1.isPremiumChecking(), false);
		t.checkExpect(pcheck2.isPremiumChecking(), true);
		t.checkExpect(credit1.isPremiumChecking(), false);
		t.checkExpect(pcheck1.isPremiumChecking(), true);
		t.checkExpect(savings1.isPremiumChecking(), false);
	}

	// Test sameChecking
	@TestMethod
	public void testSameChecking(Tester t) {
		t.checkExpect(check1.toChecking().sameChecking(check2.toChecking()),
				false);
		t.checkExpect(check2.toChecking().sameChecking(check2.toChecking()),
				true);
	}

	// Test sameCredit
	@TestMethod
	public void testSameCredit(Tester t) {
		t.checkExpect(credit1.toCredit().sameCredit(credit2.toCredit()), false);
		t.checkExpect(credit2.toCredit().sameCredit(credit2.toCredit()), true);
	}

	// Test sameSavings
	@TestMethod
	public void testSameSavings(Tester t) {
		t.checkExpect(savings1.toSavings().same(savings2.toSavings()), false);
		t.checkExpect(savings2.toSavings().same(savings2.toSavings()), true);
	}

	// Test samePremiumChecking
	@TestMethod
	public void testSamePremiumChecking(Tester t) {
		t.checkExpect(pcheck1.toPremiumChecking().samePremiumChecking(pcheck2.toPremiumChecking()),
				false);
		t.checkExpect(pcheck2.toPremiumChecking().samePremiumChecking(pcheck2.toPremiumChecking()),
				true);
	}

	// Tests the same method inside each type ofAAcount.
	@TestMethod
	public void testSame(Tester t) {
		t.checkExpect(check1.same(check2), false);
		t.checkExpect(check2.same(check2), true);
		t.checkExpect(check2.same(savings2), false);
		// Taken to the bottom.
		t.checkExpect(check2.same(pcheck1), false);
		t.checkExpect(savings1.same(savings2), false);
		t.checkExpect(savings2.same(new Savings(0005, 100,
				"Second Savings Account", 8.9)), true);
		t.checkExpect(savings1.same(check2), false);
		t.checkExpect(credit1.same(credit2), false);
		t.checkExpect(credit2.same(new Credit(0005, 100,
				"Second Credit Account", 200, 8.9)), true);
		t.checkExpect(credit1.same(check2), false);
		t.checkExpect(pcheck1.same(pcheck2), false);
		t.checkExpect(pcheck2.same(new PremiumChecking(0002, 100,
				"Second Checking Account", 50, 5)), true);
		t.checkExpect(pcheck2.same(check2), false);
		t.checkExpect(pcheck2.same(check1), false);
		// This test is the one where instanceOf causes problems,
		// because a pcheck is an instance of check.
		// In order to make it work we had to change the names to be the same
		t.checkExpect(check2.same(pcheck2), true);
	}
}
